home *** CD-ROM | disk | FTP | other *** search
- // FULLY DOCUMENTED VERSION
-
- /*
- This code is part of the VR-386 project, created by Dave Stampe.
- VR-386 is a desendent of REND386, created by Dave Stampe and
- Bernie Roehl. Almost all the code has been rewritten by Dave
- Stampre for VR-386.
-
- Copyright (c) 1994 by Dave Stampe:
- May be freely used to write software for release into the public domain
- or for educational use; all commercial endeavours MUST contact Dave Stampe
- (dstampe@psych.toronto.edu) for permission to incorporate any part of
- this software or source code into their products! Usually there is no
- charge for under 50-100 items for low-cost or shareware products, and terms
- are reasonable. Any royalties are used for development, so equipment is
- often acceptable payment.
-
- ATTRIBUTION: If you use any part of this source code or the libraries
- in your projects, you must give attribution to VR-386 and Dave Stampe,
- and any other authors in your documentation, source code, and at startup
- of your program. Let's keep the freeware ball rolling!
-
- DEVELOPMENT: VR-386 is a effort to develop the process started by
- REND386, improving programmer access by rewriting the code and supplying
- a standard API. If you write improvements, add new functions rather
- than rewriting current functions. This will make it possible to
- include you improved code in the next API release. YOU can help advance
- VR-386. Comments on the API are welcome.
-
- CONTACT: dstampe@psych.toronto.edu
- */
-
- #include "vr_types.h"
-
- #ifndef PTRBDEF
- typedef void PDRIVER;
- #endif
-
- #ifndef PTRDEF
- typedef void POINTER;
- #endif
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// VR-386 API HEADER FILE AND DOCUMENTATION ////
- //// ////
- //// 8/1/94 BY DAVE STAMPE ////
- //// ////
- /////////////////////////////////////////////////////
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// OBJECTS: AN ENCAPSULATION METAPHOR FOR ////
- //// ////
- //// CREATION AND ANIMATION OF VIRTUAL WORLDS ////
- //// ////
- /////////////////////////////////////////////////////
-
- // OBJECTS in VR-386 come in three flavors: fixed, moveable,
- // and invisible. All are pointed to by the OBJECT type.
- //
- // Fixed objects are visible but cannot be moved, and
- // make most efficient use of memory and processor time.
- //
- // Moveable objects are visible, and can be moved and
- // animated. It is possible to convert objects between
- // fixed and moveable types.
- //
- // Invisible objects are equivalent to SEGMENTS in
- // REND386, and act as invisible links in a movement tree.
- // In fact, a moveable object is simply a fixed object
- // (a VISOBJ) associated with an invisible object (SEGMENT).
-
- // An OBJECT pointer can point to either a VISOBJ or a
- // SEGMENT. You can test what the pointer actually is
- // poining to with these macros:
-
- #define is_object_visobj(p) (*((WORD *)p)&IS_VISOBJ)
- #define is_object_segment(p) (*((WORD *)p)&IS_SEGMENT)
-
- // This function is more general:
-
- // tests if object visible
- BOOL is_object_visible(OBJECT *obj);
-
- // You can test if an object is fixed with:
-
- #define is_object_moveable(p) (*((WORD *)p)&IS_MOVEABLE)
-
- // The segments used to move CAMERAs and LIGHTs, as well
- // as the body_seg and head_seg associated with the
- // VR body cannot be directly deleted, and are marked
- // as system owned. They can be identified with:
-
- #define is_system_owned(p) (*((WORD *)p)&SYSTEM_OWNED)
-
- // To use older REND386 segment functions, you must
- // convert the object to a segment. You can do this
- // conversion with the following functions:
- // (These return NULL if given a NULL argument)
-
- // pointer to VISOBJ of OBJECT: NULL if inviible object
- VISOBJ *object2visobj(OBJECT *p);
-
- // pointer to SEGMENT of OBJECT: NULL if fixed object
- SEGMENT *object2segment(OBJECT *p);
-
- // also see make_fixed_object_moveable() below.
-
- /////////////////////////////////////////////////////
- //// ////
- //// OBJECT SELECTION ////
- //// ////
- /////////////////////////////////////////////////////
-
- // OBJECTs may have several characteristics. Selected
- // objects appear highlighted (outlined in wireframe).
- // An object is selected by highlighting it, either
- // explicitly or by clicking on it with the mouse:
-
- // set highlight flag
- void highlight_object(OBJECT *obj);
-
- // resets highlight flag
- void unhighlight_object(OBJECT *obj);
-
- // tests if visible and selected
- BOOL is_object_selected(OBJECT *obj);
-
- // Some objects can be made unselectable: for example, pointers
- // or the user's body. You can test or set this with:
-
- // tests if object can be selected
- BOOL is_object_selectable(OBJECT *obj);
-
- // force object to be unselectable
- void make_object_unselectable(OBJECT *obj);
-
- /////////////////////////////////////////////////////
- //// ////
- //// OBJECT LISTS ////
- //// ////
- /////////////////////////////////////////////////////
-
- // OBJECTS are organized in several ways. For storing
- // or manipulating several objects, they can be placed
- // on an OBJLIST. This is a double-linked list allowing
- // for rapid removal. Each list has a header to allow
- // easier removal of the first object in the list. The
- // list holds the VISOBJ part of objects, and cannot hold
- // invisible objects (segments).
- // OBJLISTs are used to store loaded objects for
- // processing before they are inserted into the
- // world, and there is a list (inactive_object_list)
- // containing objects removed from the world (i.e.
- // alternative versions of objects).
- //
- // OBJLISTs should only be used to hold objects that
- // are not in the world itself, since the objects in the
- // world are held in "area" OBJLISTs, and switch between
- // OBJLISTs if they are updated or moved.
-
- // OBJLISTS headers can be created to attach objects to, or you can
- // use the pre-created system OBJLIST default_objlist:
-
- extern OBJLIST * default_objlist; // used for loading objects
- extern OBJLIST * inactive_object_list; // all objects not currently in world
-
- // create a new objlist
- OBJLIST *new_objlist();
-
- // These functions dispose of OBJLIST headers
- // If the list is not empty, they keep or destroy
- // the VISOBJs on the list
-
- // delete objects on list then delete objlist
- void delete_objlist_and_objects(OBJLIST *list);
-
- // delete objlist, but just remove objects from list
- // safer if not sure all objects are off list
- void delete_objlist_keeping_objects(OBJLIST *list);
-
- // These functions place or remove objects to an OBJLIST.
- // It is not recommended to handle world objects diectly:
- // remove or add objects to the world using functions in
- // the WORLD section first:
-
- // drop object from list it's on
- void remove_from_objlist(OBJECT *obj);
-
- // put object at head of list
- // remove if already on any list
- void add_to_objlist(OBJLIST *list, OBJECT *obj);
-
- // Merging OBJLISTS is safe: Especially useful to add
- // lists of loaded objects to the inactive_object_list
-
- // removes all from <from>, adds to start of <to>
- void merge_objlists(OBJLIST *from, OBJLIST *to);
-
- // In many cases, you need to perform a function on all
- // objects in a list. Leter we will see similar "walking"
- // functions for object trees and the world.
-
- void walk_objlist(OBJLIST *objlist, void (*fn)(OBJECT *));
-
- // These are object list-status functions, included for completeness
-
- // is it currently in a list?
- BOOL on_any_objlist(OBJECT *obj);
-
- // look for head of list object is in.
- OBJLIST *which_objlist(OBJECT *obj);
-
- OBJECT *first_in_objlist(OBJLIST *objlist);
- OBJECT *next_in_objlist(OBJECT *obj);
- OBJECT *prev_in_objlist(OBJECT *obj);
- BOOL is_first_in_objlist(OBJECT *obj);
- BOOL is_last_in_objlist(OBJECT *obj);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// OBJECT TREES, ATTACHMENT AND LINKED MOTION ////
- //// ////
- /////////////////////////////////////////////////////
-
- // OBJECTS may be attached to each other for the purpose
- // of controlling motion. The links between objects are
- // "joints", which may be moved or rotated. Many objects
- // can descend from one "parent" object, and will all move
- // as if part of the parent object when it moves, with
- // additional effects from their own joints.
- //
- // Effectively, there are two "poses" (combinations of
- // position and rotation) for each object: the "local"
- // or "joint" position, which is the difference between
- // the parent and "child" object poses. The "world" pose
- // is the actual pose that the object has in the world,
- // which is the composite of the parent object's world pose
- // and the joint pose of the object.
- //
- // An object tree can be considered to be a single articulated
- // object, with the "root" object being used to move the object
- // in the world. This root object (and any object in the tree)
- // may be visible or invisible.
-
- // The basic operation is to attach and detach objects from the
- // tree. Because the pose of the object depends on that of its
- // parent object, the joint pose is rarely the same as that of
- // the world pose when the object is attached. So we must choose
- // whether to preserve the joint or world pose of an object when
- // attaching or detaching it. While we could always choose to
- // preserve world pose when attaching or detaching objects, it's
- // somewhat expensive on processor time since we may want to immediately
- // reset the joint pose of the object.
-
- /* assumes parent is updated! */
- // preserves world position if flagged
- void attach_object(OBJECT *obj, OBJECT *to, BOOL preserve);
-
- // this is the least expensive attach, and
- // does no updates or calculations
- // be sure to update <to> later!
- void naked_attach_object(OBJECT *obj, OBJECT *to);
-
- // detaches object: preserves world position if flagged
- void detach_object(OBJECT *obj, BOOL preserve);
-
- // Here are some informational functions for object trees:
-
- // finds the basic object of a tree
- OBJECT *find_root_object(OBJECT *obj);
-
- // tests relationship of objects
- BOOL is_object_child_of(OBJECT *parent, OBJECT *child);
-
- // tests for any relationship of objects
- // i.e. are they in the same tree?
- BOOL are_object_related(OBJECT *o1, OBJECT *o2);
-
-
- // Much like the OBJLIST-walk functions, these functions will
- // execute a function for each object in the tree. They can
- // process objects that have certain characteristics. They can either
- // process the given object and its decendants, or all objects
- // in the same tree as the object.
-
- // object and children:
-
- // execute for object and descendants
- void do_for_all_child_objects(OBJECT *obj, void(* fn)(OBJECT *));
-
- // execute for objects and descendants-- ONLY visible objects
- void do_for_visible_child_objects(OBJECT *obj, void(* fn)(OBJECT *));
-
- // execute for objects and descendants-- ONLY highlighted objects
- void do_for_selected_child_objects(OBJECT *obj, void(* fn)(OBJECT *));
-
- // all objects in tree:
-
- // execute for entire object tree-- ONLY visible objects
- void do_for_visible_related_objects(OBJECT *obj, void(* fn)(OBJECT *));
-
- // execute for entire object tree
- void do_for_all_related_objects(OBJECT *obj, void(* fn)(OBJECT *));
-
- // execute for entire object tree-- ONLY highlighted objects
- void do_for_selected_related_objects(OBJECT *obj, void(* fn)(OBJECT *));
-
-
- // You may also want to delete the objects in the tree
- // completely. This can be done for the children of the
- // object, or for the entire tree if find_root_object(obj) is
- // used.
-
- // delete object, descendents and objects
- void delete_object_and_children(OBJECT *obj);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// OBJECT POSE, MOTION AND UPDATING ////
- //// ////
- /////////////////////////////////////////////////////
-
- // OBJECT motion in VR-386 has several stages to increase efficiency.
- // In the first stage, moveable objects may have their "pose"
- // (position and rotation) modified individually. Since any
- // descendent object may have their position affected by this,
- // the effect of all motions must be propagted through the tree
- // by and update step. (This step is done automatically by
- // animation functions, as we'll see later).
- //
- // Finally, the renderer will determine which objects are visible
- // and complete the movement of the object by recomputing their
- // vertex positions. Each vertex in a VR-386 object has two
- // sets of coordinates: object (ox,oy,oz) which determine the object
- // shape, and world (x,y,z) which are updated by the renderer by
- // computing them from object world pose and the object coordinates.
- //
- // Internally, the SEGMENT part of an object contains two matrices:
- // a world-position (pmatrix) and a joint position (jmatrix).
- // The world matrix is modified by any motions of objects theat the
- // object is attached to; the jmatrix is modified by setting object
- // pose or by attaching/detaching the object from others.
- // To find the true pose of the object (world or joint) may require
- // that we look at the angles in the matrix rather than the cached
- // record of the last pose change. This is somewhat more expensive,
- // but is sometimes needed..
-
- // A POSE is the basic structure used for movement in VR-386.
- // It has the following definition:
- //
- // typedef struct {
- // COORD x,y,z;
- // ANGLE rx,ry,rz;
- // } POSE;
- //
- // A special value for the fields of the POSE is:
- //
- #define DONTCARE 0x80000000L
- //
- // which says that the position or angle of that entry is unspecified,
- // and (if the POSE is being applied to an object) that the value
- // of that part of the current object pose will not be changed.
- //
- // Two predefined values for initializing POSE structures are defined:
-
- #define DONTCARE_POSE { DONTCARE,DONTCARE,DONTCARE,DONTCARE,DONTCARE,DONTCARE }
- #define ZERO_POSE { 0,0,0,0,0,0 }
-
- // For example, most POSE structures should be initialized to ZERO_POSE.
- // You can use DONTCARE_POSE initialization if you're only going to be
- // changing a few field of the object pose, for example:
- //
- // POSE p, pp = DONTCARE_POSE;
- // get_object_pose(obj, &p);
- // pp.rx = p.x + float2angle(5);
- // set_object_pose(obj, &pp);
- //
- // which will increase the rotation angle about the X axis of the object's
- // joint (or world, if the object is unattached) by 5 degrees.
-
- // Here are object pose functions:
-
- // get local "joint" pose of object if moveable
- void get_object_pose(OBJECT *obj, POSE *p);
-
- // get "real" pose from joint matrix in object
- void get_object_matrix_pose(OBJECT *obj, POSE *p);
-
- // get global physical pose of object from world matrix
- void get_object_world_pose(OBJECT *obj, POSE *p);
-
- // set the "joint" pose of object
- // ignores DONTCARE values in pose
- void set_object_pose(OBJECT *obj, POSE *p);
-
- // place object in world, even if attached!
- // can be expensive, especially if DONTCARES used
- void set_object_world_pose(OBJECT *obj, POSE *p);
-
- // faster way to get object position than world_pose
- void get_object_world_position(OBJECT *obj, COORD *x, COORD *y, COORD *z);
-
- // There are also a lot of older SEGMENT-based REND386 functions available.
- // If you use these, be sure to use object2segment() to do the
- // translation first!
-
- // Updating of the object tree proceeds from the specified object
- // down through its descendents. The objects are scanned to see
- // if any have changed: if so, the world pose of the changed
- // object and all its descendents are recomputed.
- //
- // Updating is also essential if an object has been changed
- // in any way, so that the changes will be registered to the
- // world position. Major changes (e.g in object scale or
- // changes in object vertex positions) will require more
- // drastic "physical" updating. These will be discussed further
- // for object creation and loading:
-
- // checks if moved; recomputes world position
- void update_object(OBJECT *obj);
-
- // recomputes object normals, bounding sphere
- // and if moved: current representation only
- void physical_update_object(OBJECT *obj);
-
- // massive update: recomputes all object's reps,
- // forces all connecting objects to update position
- void global_update_object(OBJECT *obj);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// ANIMATION AND AUTOMATIC UPDATING ////
- //// ////
- /////////////////////////////////////////////////////
-
- // NOT FULLY COMPLETED: ALL LISTED ARE FUCTIONAL
-
- // Animation control is a set of functions to allow autonomous
- // motion of objects without the need to move objects each
- // frame. In the future, functions such as TWEEN will be added.
- // As of now, the critical step is an auto-update system for
- // efficient calculation of changed objects, used by STATMACH.C
- // for now.
- //
- // When many joints of a figure (objects in a tree) are moved
- // it is crucial not to update each joint individually, as this
- // would cause objects to be recomputed many times. Instead,
- // a list is created of the root objects of the tree of moved
- // objects. Then after all animation is complete, the object
- // updates may be done quickly. YOU are responsible for updating
- // moved objects unless the animation system has moved them!
- //
- // Objects are automatically updated when attached or detached.
- // Because the tree structure is changed, during animation it
- // is important to do any attach or detach operations BEFORE
- // moving objects.
-
- // puts root of tree on update list if not there
- // just pass the object that was move: the code will do the rest
- void add_to_object_update_list(OBJECT *obj);
-
- // does the update on all moved objects, then
- // removes them from the update list
- // returns nonzero if update was needed, so
- // you can tell if rendering is needed.
- BOOL process_object_update_list();
-
- // Sometimes objects must be removed from the list: before
- // deleting objects or worlds, for example. Usually it's
- // better to simply process the list.
-
- // fast remove deleted segments
- void remove_from_object_update_list(OBJECT *obj);
-
- // dump entire update list
- void clear_object_update_list();
-
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// THE WORLD ////
- //// ////
- /////////////////////////////////////////////////////
-
- // UNDER CONSTRUCTION: NOT ALL FULLY FUNCTIONAL
-
- // In VR-386, a WORLD serves to organize a set of objects into
- // an environment. Eventaully, this environment may be loaded
- // or deleted, or the user may switch between worlds.
- //
- // For objects, the world is a visibility structure (a SPLIT tree),
- // containing all visible objects in to world. Objects that are
- // not visible (e.g. alternate forms of an object) should be
- // placed in the inactive_object_list OBJLIST, so they may be
- // deleted when the world is terminated. Or they may just be
- // left off any list, if you take responsibility for their
- // deletion. Note that only VISOBJ (visible part of moveable
- // or fixed objects) are part of the world: invisible objects
- // (SEGMENTS) are not so you must use care to delete them
- // when disposing of a world.
- //
- // The visibility tree consists of SPLITs: 3-D planes that divide
- // the world into AREAs. As yet, there is little support in the
- // API for AREAs: there is a lot of work to be done on and with
- // them in the future.
- //
- // For now, you should be able to:
- // -create the startup, default WORLD (TESTED)
- // -make new WORLDs (but be careful loading them!) (??)
- // -switch between WORLDS (??)
-
- // These are the currently defined WORLD functions:
-
- // save current camera, visibility tree, inactive list,
- // and user position to WORLD w
- void save_world_state(WORLD *w);
-
- // restore old WORLD w
- void restore_world_state(WORLD *w);
-
- // create WORLD, save current WORLD data to it
- // <template> arg not yet used
- WORLD *create_world(WORLD * template);
-
- // just releases WORLD struct now
- // In the future, will delete everything in the world
- void release_world(WORLD *w); // NOT YET FUNCTIONAL
-
- // for initialization, creates all the default
- // objects, structures, lists and so on
- // creates a WORLD <default_world>
- void create_default_world();
-
- // DON'T USE until a better world file format is developed!
- // for now, use read_world() to load a REND386 compatible
- // world.
- void load_world(FILE *in, WORLD *w); // NOT FUNCTIONAL
-
- // These items are manipulated by changing the WORLD, and
- // form the roots of world structures:
-
- extern WORLD *default_world; // the default world (startup)
- extern WORLD *current_world; // the WORLD currently in use
-
- extern SPLIT *global_world_root; // the root of current visibility tree
- extern SPLIT *current_split; // used to add objects to splits
-
- extern OBJLIST *default_objlist; // used for loading objects
- extern OBJLIST *inactive_object_list; // all objects not currently in world
-
-
- // Objects when first loaded are not part of the world. Objects
- // must be explicitly added to the world to become visible, and must
- // be removed from the world to make them invisible.
-
- // To add objects to the world, use these functions:
-
- void add_object_to_world(OBJECT *obj);
-
- void add_objlist_to_world(OBJLIST *olist);
-
- // Use this function to remove an object from the world. The
- // objects will be placed in the inactive_object_list OBJLIST.
-
- void remove_object_from_world(OBJECT *obj);
-
- // When creating worlds with walls or other visibility-error prone
- // features, SPLITs must be used. They are also useful for dividing
- // the world into AREAs. A SPLIT is a plane, specified by a point
- // on it and a normal to its surface. Normals values should be
- // as large as possible: perhaps use a unit normal and convert it
- // with float2matval(). Set <flags> to zero for now. The point
- // (x,y,z) should be somewhere near the center of the useful area of
- // the split, since it will be used to determine the AREA of the
- // world the split will subdivide.
- //
- // Any objects added to the world after a SPLIT has been created will
- // be attached to that SPLIT: for example, you'd create a split for
- // a room side then add an object to the world for that side of the room.
- // Once all SPLITs have been created and their objects loaded, call
- // end_of_world_splits(). All objects loaded after this will be
- // placed within AREAs.
- //
- // If not using SPLITs, just ignore them. A default SPLIT at infinity
- // is created for each new world.
-
- // Adds a split to the WORLD.
- // return FALSE if can't create it.
- BOOL add_split_to_world(COORD x, COORD y, COORD z,
- COORD nx, COORD ny, COORD nz, WORD flags);
-
- // Marks end of SPLIT object loading, start of
- // loading of rest of world objects.
- BOOL end_of_world_splits();
-
-
- //////// WORLD OBJECT TRAVERSALS
- // You often need to process all objects in the world
- // (usually to count objects, or to process selected
- // objects). These functions apply a function to all
- // objects in the world.
-
- // for all objects not currently in world...
- void do_for_all_not_in_world(void (*fn)(OBJECT *));
-
- // for all objects in world...
- void do_for_all_objects(void (*fn)(OBJECT *));
-
- // for all selected (highlighted) in world...
- void do_for_all_selected(void (*fn)(OBJECT *));
-
- // for all moveable in world...
- void do_for_all_moveable(void (*fn)(OBJECT *));
-
- // for all fixed in world...
- void do_for_all_fixed(void (*fn)(OBJECT *));
-
- // for all selected, moveable in world...
- void do_for_all_selected_moveable(void (*fn)(OBJECT *));
-
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// LOADING OBJECTS AND FIGURES ////
- //// ////
- /////////////////////////////////////////////////////
-
- // Objects in VR-386 are loaded as fixed objects, and are not
- // placed into the world. You are responsible for placing the
- // objects into the world when you wish them to become visible.
- // Or you can place them onto the inactive_object_list OBJLIST
- // until needed.
- //
- // Objects are loaded from PLG files, which nmust have been
- // opened previously. You can also load out of ANY text file:
- // for example, out of the middle of a world or .FIG file. This
- // has not been used yet. A change from REND386 .PLG files is
- // that the sum of the vertex counts for all polygones is needed.
- // This is an extra argument in the header line of the PLG file.
- // If no number is supplied, the file will be read twice.
- //
- // Objects loaded from PLG files are first scaled, then shifted
- // and finally rotated to create the vertices of the object.
- // Negative scales should NEVER be used, as visibility problems
- // will result. The PLG vertex coordinates may be in floating point,
- // as are the scaling factors. The rotation and shift affect the
- // "object-space" representation of the object, before it is moved
- // in the world. This is similar the the <shift> in .FIG files, and
- // unlike the shift and rotate for moveable objects in REND386 .WLD
- // files. The most important use for this is to position fixed objects
- // in the world, and to set the origin (0,0,0) point of objects, as this
- // is where it will rotate around when moved.
- //
- // The <depth> parameter says how the object will be sorted when
- // rendered. 0 will let the object's polys be sorted by deepest vertex,
- // 1 will cause them to be sorted by vertex midpoint. Set bit 0x0100 to
- // have the object sorted as a unit, then polys within it sorted.
- // THE DEPTH PARAMETER WILL HAVE NEW FUNCTIONS IN THE FUTURE.
- //
- // Some objects may have multiple representations. A representation
- // (REP) is the descripton of the visible part of an object, and
- // consists of its polys, colors, and vertices.
- // Multiple representations are usually used to increase rendering speed,
- // by letting distant (small) objects disappear or be drawn in a simpler
- // form than when close and large. The size in pixels that the object
- // must subtend on the screen to be visible is set by the "size"
- // parameter, which may be set in the PLG file in the object name.
- // A representation of size 0 will always be seen, while larger "size"
- // representations can disappear if too small. Use a size of 0 if not
- // using this feature.
- //
- // Additional representation can be used for "morphing" animations.
- // The representation to be visible can be "locked" as the one to
- // be drawn at all times, and a sequence of representations used for
- // animation.
- // To specify that an object has multiple representations, precede
- // the header line of the PLG object with "##MULTI". Do this for
- // all PLG objects to be used as additional representations, except
- // the last one. In other worlds, the first PLG without ##MULTI will
- // be the last representation loaded.
-
- // This is the simplest function, simply loading the first PLG
- // object found in a file. It can load multiple representations.
- // Call add_object_to_world(obj) to place object in the world.
-
- // loads single and multi-rep files
- // will load only one object: call again if not EOF
- OBJECT *load_plg_object(FILE *in, POSE *p,
- float sx, float sy, float sz, WORD depth);
-
- // This function adds an extra representation to an existing object.
- // It can add several representations if ##MULTI is used. Be sure
- // to call physical_update_object(obj) after this so the new representation
- // will be properly visible!
-
- // loads a new rep to an old object.
- // useful to create morphing animations
- // just loads FIRST if not multi-rep file
- // Uses <size> parameter to set size field
- OBJECT *load_extra_plg_representation(FILE *in, OBJECT *obj, POSE *p,
- float sx, float sy, float sz, WORD size);
-
- // When a complex object consisting of many pieces is loaded, or there
- // are many objects in a PLG file to be loaded, it is useful to load
- // the objects onto an OBJLIST. This will allow us to process the
- // object(s) as a unit later on. For example, the objects can be placed into
- // the world as a unit, or recolored etc. A group of simple objects
- // may be attached to an invisible "handle" object so they can be moved as a
- // unit. Usually, the precreated OBJLIST default_objlist will be used for
- // loading and processing objects.
-
- // loads single and multi-rep files
- // will load many objects
- // loads to objlist for later recoloring etc
- // loads as fixed objects so can be joined
- // can limit number to load (so multi objects from file)
- // returns number of objects in list
- WORD load_plg_to_objlist(FILE *in, OBJLIST *objlist, WORD maxobj, POSE *p,
- float sx, float sy, float sz, WORD depth);
-
- // These functions are used to make loaded, fixed objects moveable. It
- // does this by attaching a SEGMENT (invisible, moveable object) to them.
- // The object may then be processed as a unit.
-
- // converts loaded fixed object to moveable
- // adds as visible part to invisible object if supplied
- // if NULL, creates the invisible object part
- OBJECT *make_fixed_object_moveable(OBJECT *obj, OBJECT *invis);
-
- // creates moveable object-group from objects in list
- // joins multiple objects to new invisible object
- // which acts as a handle to move the group.
- OBJECT *convert_objlist_to_moveable_object(OBJLIST *olist);
-
- // disconnects visible part of object from
- // invisible object, returns visible part.
- // invisible part is stored in **invis.
- // <preserve> sets whether to leave fixed
- // object in same world positon-- DON'T USE
- // if you are going to make object moveable again!
- OBJECT *make_moveable_object_fixed(OBJECT *obj, OBJECT **invis, BOOL preserve);
-
-
- // Complex jointed object structures are important for animation
- // e.g. human figures. The .FIG file format allows specification of
- // figures that can be loaded as a unit, then manipulated.
- // Currently, loaded segment files can only be scaled, and are
- // placed in position by moving their "handle" or root object.
- //
- // For animation, it is critical that the various objects in
- // the figure be able to be identified. There are two ways to do
- // this. An object may be named in the .FIG file, and the name
- // searched for later with find_seg_by_name(object2segment(obj),"name")
- // Or, you can set up a table: OBJECT *segtable[stmax] to hold pointers
- // to the objects, that will be filled as the file is read, from "segnum"
- // lines in the file.
-
- // load a .FIG file as an object tree
- // resulting tree root is returned
- // objects are not in world and held in objlist
- // "segnum" entries put pointers into <segtable>
- OBJECT *load_figure_as_object(FILE *in, OBJLIST *olist, OBJECT **segtable,
- WORD stmax, float sx, float sy, float sz);
-
- // For error reporting, either an error number of a pointer to an
- // error message is returned. These functions are provided:
-
- // load error report from .FIG file load:
- // returns NULL if no error
- char *seg_error(SWORD *errnum);
-
- // load error report from .PLG file load:
- // returns NULL if no error
- char *plg_error(SWORD *errnum);
-
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// CREATING OBJECTS FROM SOFTWARE ////
- //// ////
- /////////////////////////////////////////////////////
-
- // Creating an invisible object (used as part of a motion tree)
- // is simple:
-
- OBJECT *create_invisible_object();
-
- // Creating a visible object is more complex, since the visible
- // part of the object must be specified. YOU MUST NEVER ATTEMPT
- // TO ACCESS AN OBJECT REPRESENTATION DIRECTLY, AS IT MAY BE
- // STORED IN PAGED EXTENDED MEMORY! See EMMSPPT.C for more
- // information.
- //
- // To allocate memory, each representation needs to know the total
- // number of polygons, vertices, and polygon vertices.
- //
- // Creating an object in software requires a series of steps:
- //
- // -create an object (automatically creates first representation)
-
- OBJECT *create_fixed_object(WORD nv, WORD np, WORD npverts);
-
- OBJECT *create_moveable_object(WORD nv, WORD np, WORD npverts);
-
- // -add all vertex points to the object
-
- // adds vertex to object: these aren't yet hooked to polys
- void add_vertex(OBJECT *obj, COORD x, COORD y, COORD z);
-
- // -for each polygon:
- // --create new polygon
-
- // adds poly to rep: still needs vertex list defined
- POLY *add_poly(OBJECT *obj, SURFACE color, WORD npoints);
-
- // --add points (polygon vertices, as indexes into vertex table)
-
- // connects vertices to polys thru vertex lists
- void add_point(OBJECT *obj, POLY *p, WORD vertindex);
-
- //
- // -for every additional representation, create it, then
- // repeat the last 4 steps
-
- REP *add_representation(OBJECT *obj, WORD size, WORD nv, WORD np, WORD tpverts);
-
- // After creating the object, you must compute cached data for the
- // object: its bounding sphere, and each of it's polygon's normals.
- // Use these functions after creating an object:
-
- // The compute_object() functions are OK if the object will
- // be placed into or moved within the world immediately.
-
- // Use this for each or last-added representation:
-
- // computes renderer data for object
- // for current rep only!
- void compute_object(OBJECT *obj);
-
- // Use this if you've added more than one rep to an object
-
- // computes renderer data for object
- // for all representations
- void compute_all_object(OBJECT *obj);
-
- // this also takes care of wolrd and location updates
- // caused by changing an object, and is safer.
-
- // recomputes object normals, bounding sphere
- // and if moved: current representation only
- void physical_update_object(OBJECT *obj);
-
- // If speed is no problem, global_update_object is safest.
-
- // massive update: recomputes all object's reps,
- // forces all connecting objects to update position
- void global_update_object(OBJECT *obj);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// OBJECT SUPPORT: REPRESENTATION CONTROL ////
- //// ////
- /////////////////////////////////////////////////////
-
- // Some objects may have multiple representations. A representation
- // (REP) is the descripton of the visible part of an object, and
- // consists of its polys, colors, and vertices.
- // Multiple representations are usually used to increase rendering speed,
- // by letting distant (small) objects disappear or be drawn in a simpler
- // form than when close and large. The size in pixels that the object
- // must subtend on the screen to be visible is set by the "size"
- // parameter, which may be set in the PLG file in the object name.
- // A representation of size 0 will always be seen, while larger "size"
- // representations can disappear if too small. Use a size of 0 if not
- // using this feature.
- //
- // Additional representation can be used for "morphing" animations.
- // The representation to be visible can be "locked" as the one to
- // be drawn at all times, and a sequence of representations used for
- // animation.
- //
- // In some cases, access to a specific representation
- // is required. The representations on an object are
- // in a list, with "largest" <size field> first.
- // Representation of the same size are stored last-first.
- // One of the representations will be "current" at any time,
- // and is the only one that may be manipulated.
-
- // make first rep the current one: used during lock
- void select_first_representation(OBJECT *obj);
-
- // make next rep the current one: used during lock
- /* return 1 if wrapping back to first */
- WORD select_next_representation(OBJECT *obj);
-
- // find representation that will be
- // active at given screen size
- void select_representation(OBJECT *obj, WORD size);
-
- // These functions are the heart of morphing animations.
-
- // forces renderer to always draw rep
- // if n = 0, it will be the current rep
- // Otherwise, it's the Nth representation
- void lock_current_representation(OBJECT *o, WORD n);
-
- // goes back to select-by-size mode
- void unlock_current_representation(OBJECT *o);
-
- // Sometimes, you need to change the size field of a representation
-
- // set size field of rep
- void set_representation_size(OBJECT *obj, WORD size);
-
- // read size field
- WORD get_representation_size(OBJECT *obj);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// OBJECT SUPPORT: CHANGING COLOR AND SURFACE ////
- //// ////
- /////////////////////////////////////////////////////
-
- // VR-386 is flexible enough to use many methods of coding
- // colors and surface types (see COLORMAP.C for details
- // of the current hue/reflectance method, similar to that
- // used by REND386).
- // You should use SURFACE as the type for all color/surface specifiers,
- // to improve compatibility with future upgrades, since 32-bit or
- // pointers may be needed for RGB colors or texture mapping in the future.
- //
- // There are two recoloring methods used: one is a global "change everything"
- // strategy, and the other can change sets of colors to other colors
- // selectively. This last uses an array of SURFACEPAIRS, as:
- //
- // typedef struct { // pair for surface remapping
- // SURFACE old;
- // SURFACE new;
- // } SURFACEPAIR;
- //
- // The matching and replacement of bits in the process are controlled
- // by masks, making it easy to change only the hue field of the
- // surface description, or to select a polygon for recoloring by the
- // 3 LSB of its brightness field. These bits can be preserved by
- // the write mask.
-
- // This function modifies all polygons in an object. Where bits in
- // <bitmask> are set, bits from <new> replace current surface bits
- // in the polygon. The <all> flag, if set, processes ALL representations
- // of the object, otherwise only the current representation is processed.
-
- // flexible recolor/resurface object
- void masked_recolor_object_surface(OBJECT *obj, SURFACE new,
- SURFACE bitmask, BOOL all);
-
- // This function modifies only polygons whose current surface matches
- // one of the SURFACEPAIR.old in <map>. Only bits where <sbitmask>'s bits
- // are set are used in the comparison. Only the set bits in <dbitmask>
- // from the pair's .new field will replace current surface bits
- // in the polygon. The <all> flag, if set, processes ALL representations
- // of the object, otherwise only the current representation is processed.
-
- // very flexible remaps colors of object
- void masked_remap_object_surface(OBJECT *obj, SURFACEPAIR map[20], WORD nmap,
- SURFACE sbitmask, SURFACE dbitmask, BOOL all);
-
- #define MAP_ALL_MASK 0xFFFF // some useful masks
- #define IGNORE_HIGHLIGHT_MASK 0x7FFF
- #define MAP_SURFACE_MASK 0x3000 // test/modify surface type only
- #define MAP_HUE_MASK 0x0F00 // test/modify hue only
- #define MAP_BRIGHTNESS_MASK 0x00FF // test/modify brightness only
- #define MAP_PALETTE_MASK 0x00FF // test/modify abs. 256 color palette entry
-
- #define TEST_B3BITS_MASK 0x0007 // test 3 LSB as "type" code
- #define KEEP_B3BITS_MASK 0xFFF8 // keep the 3 LSB as "type" code
-
- // When loading objects, we want to be able to process all the objects
- // and their representations immediately. The objects are in an
- // OBJLIST, and it is most convenient to use this function when loading
- // objects:
-
- // very flexible remaps colors
- // does for all objects in objlist
- void objlist_remap_surface(OBJLIST *olist, SURFACEPAIR map[20], WORD nmaps,
- SURFACE sbitmask, SURFACE dbitmask);
-
- // The standard PLG remapping used in REND386 used 0x80xx as the "raw"
- // color number, with "xx" being the number in the surfacemap. It is
- // trivial to set up a SURFACEPAIR table to do this replacement: set the
- // MSB of the .old color numbers, and the .new is the desired surface.
- // Use MAP_ALL_MAP for <sbitmask> and <dbitmask>.
-
-
- // For direct color access into polygons, these low-level functions
- // are supplied:
-
- // get data on poly
- // use poly number ito object
- // use NULL for *color and *nverts
- // if you don't want their data
- void get_poly_info(OBJECT *obj, WORD polynum, SURFACE *color, WORD *nverts);
-
- // set poly's color number
- void set_poly_color(OBJECT *obj, WORD polynum, SURFACE color);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// OBJECT SUPPORT: DELETIONS ////
- //// ////
- /////////////////////////////////////////////////////
-
- // In most cases, objects are not deleted individually.
- // Usually an entire movement tree, OBJLIST or world
- // visiblilty tree is deleted at once. More deletions
- // support will be available when world deletion is complete.
-
-
- // This function deltes the visible part of a moveable
- // object, or a fixed object entirely. It is best used
- // for deletions when you're not sure if the segment
- // of the object is in use elsewhere.
-
- // deletes fixed object or
- // visible part of moveable object
- // also removes from any objlist
- void delete_visobj(OBJECT *obj);
-
- // This function deletes invisible, visible or moveable
- // objects. It cannot delete objects that are registered
- // as system-owned, such as the segments of cameras or lights.
- // Delete these with delete_light() or delete_camera()
-
- // can delete segments or visobjs, but not if
- // the segment is system owned (camera, light)
- // also removes from any objlist
- void delete_object(OBJECT *obj);
-
- // object list deletions:
-
- // delete objects on list then delete objlist
- void delete_objlist_and_objects(OBJLIST *list);
-
- // delete objlist, but just remove objects from list
- // safer if not sure all objects are off list
- void delete_objlist_keeping_objects(OBJLIST *list);
-
- // You may also want to delete the objects in the tree
- // completely. This can be done for the children of the
- // object, or for the entire tree if find_root_object(obj) is
- // used.
-
- // delete object, and descendent objects
- // both moveable and invisinble objects deleted
- void delete_object_and_children(OBJECT *obj);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// OBJECT SUPPORT: MISCELLANEAOUS ////
- //// ////
- /////////////////////////////////////////////////////
-
- // Every visible object has a bounding sphere. This function
- // reports the world position of its center and its radius.
-
- COORD get_object_bounds(OBJECT *obj, COORD *x, COORD *y, COORD *z);
-
- // get data on poly of object
- void get_poly_info(OBJECT *obj, WORD polynum, SURFACE *color, WORD *nverts);
-
- // set surface type of object poly
- void set_poly_color(OBJECT *obj, WORD polynum, SURFACE color);
-
- // gets number of vertices, polys for current rep
- void get_obj_info(OBJECT *obj, int *nv, int *np);
-
- // sum of number of vertices of all polys for current rep
- WORD total_object_pverts(OBJECT *obj);
-
- // get/set object dorting type (see LOADING...)
- WORD get_object_sorting(OBJECT *obj);
- void set_object_sorting(OBJECT *obj, WORD depth_type);
-
- // vertices are referenced in two ways: as an entry in the object's
- // vertex table, and as the vertex number of a polygon.
- // This fuctions converts a polygon's vertex number (0..n-1)
- // to the index in the vertex table.
-
- WORD get_poly_vertex_index(OBJECT *obj, WORD poly, WORD vertex);
-
- // To actually modify the shape of an object, it is only really
- // feasible to move the vertices. These functions will allow
- // the object's internal vertex coords to be accessed and modified.
- // Don't forget to call physical_object_update() after changing
- // the object.
-
- void get_vertex_info(OBJECT *obj, WORD vertnum, COORD *x, COORD *y, COORD *z);
- void set_vertex_coords(OBJECT *obj, int vertnum, COORD x, COORD y, COORD z);
-
- // This function scales the size of an object. You must call
- // physical _update_object afterwards. Not useful with small objects,
- // and precision is lost after each scaling. Mostly useful for
- // setting up objects.
-
- void scale_object(OBJECT *obj, float sx, float sy, float sz);
-
- // When an existing object must be moved or rotated internally,
- // (NOT in the usual way), then its internal representation
- // must be changed. Precision will be lost, of course. But
- // the best way to do this is to use a homogenous matrix to
- // move the world position of the object, then to copy the
- // world vertex positions into the "object" vertex information.
- // The matrix may be derived from a segment, or may be generated by
- // one of the routines in the INTMATH library.
-
- void apply_matrix(OBJECT *obj, MATRIX m); // moves object completely
- void copy_world_to_object(OBJECT *obj); // used to "lock" fixed objects
-
- // Once a visible object has been rendered, the world coordinates
- // for each of its vertices is cached internally. This routine
- // can extract that information for use in collision detection
- // or other routines.
-
- void get_vertex_world_info(OBJECT *obj, WORD vertnum, COORD *x, COORD *y, COORD *z);
-
- // This function scans an OBJLIST, looking for the object whose center
- // closest to the given world point. It only chacks objects whose
- // bounding sphere includes the point of interest. Usually it is used in
- // combination with world areas (see MANIP3D.C for an example).
-
- // determines closest object in list
- OBJECT *best_collision(OBJLIST *objlist, COORD x, COORD y, COORD z);
-
- // At oresent, there are NO user-manipulable flags in the
- // objects. There may be a user flag word in the future.
-
- void set_obj_flags(OBJECT *obj, WORD val);
-
- WORD get_obj_flags(OBJECT *obj);
-
- // set/clear flags in visobj part of object
- void set_object_flags(OBJECT *obj, WORD flagmask, WORD bitval);
-
- // For completeness, the object-update functions are listed here:
-
- // recomputes object normals, bounding sphere
- // and if moved: current representation only
- void physical_update_object(OBJECT *obj);
-
- // massive update: recomputes all object's reps,
- // forces all connecting objects to update position
- void global_update_object(OBJECT *obj);
-
- // converts loaded fixed object to moveable
- // adds as visible part to invisible object if supplied
- OBJECT *make_fixed_object_moveable(OBJECT *obj, OBJECT *invis);
-
- // creates moveable object-group from objects in list
- // joins multiple objects to new object
- OBJECT *convert_objlist_to_moveable_object(OBJLIST *olist);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// CAMERAS, STEREOSCOPIC SUPPORT (SCAMERA.C) ////
- //// ////
- /////////////////////////////////////////////////////
-
- // A CAMERA is a device for reproducing a monoscopic
- // or stereoscopic view of the world to the screen.
- // The camera may be moved like any object, or
- // attached to any object. A special CAMERA,
- // default_camera, is created and set up during
- // configuration to use as a template (in many programs,
- // this may be the only camera used). Usually the default camera is
- // attached to the "body" object's "head" object
- // for use with head trackers and HMDs
-
- // The default_camera is created at initialization, and is modified
- // during configuration. The current_camera will be used for
- // rendering and view-dependant calculations.
-
- extern CAMERA * default_camera; // the "basis" camara for world
- extern CAMERA * current_camera; // the current camera used for rendering
-
- // creates, initializes camera
- // may be stereo or mono, may copy another camera
- CAMERA *create_camera(BOOL is_stereo, CAMERA *template);
-
- // delete camera, free memory
- void destroy_camera(CAMERA *c);
-
- // These commect and disconnect the camera from objects that
- // can move the camera in the world:
-
- // attach camera to moveable object
- void attach_camera(CAMERA *c, OBJECT *obj);
-
- // detach camera
- void detach_camera(CAMERA *c);
-
- // These functions manipulate camera pose. Recall that
- // local and world pose are the same if the camera is
- // not attached to anything: the default_camera is
- // always attached to body_seg, so the local pose is the head-to-body
- // angle of the head tracker, and the world pose is the "real"
- // viewpoint and look angle.
-
- // set camera pose (if attached, set relationship)
- void set_camera_pose(CAMERA *c, POSE *p);
-
- // get pose with relation to object attached to
- void get_camera_localpose(CAMERA *c, POSE *p);
-
- // get world position/angle
- void get_camera_worldpose(CAMERA *c, POSE *p);
-
- // Certain operations must be done with respect to the camera's view
- // itself. For example, mouse and 3D pointer operations must
- // take place in the camera's view coordinates so that motion in
- // the world and on the screen always match. When loading PLG
- // files, we want to place the object "ahead" of the camera so it
- // appears a constant size... and so on.
-
- // get the MONOSCOPIC camera pose matrix
- // usually best match for stereoscopic cameras as well
- void get_camera_matrix(CAMERA *c, MATRIX m);
-
- // computes coords of point in fromnt of MONOSCOPIC camera
- void camera_point_ahead(CAMERA *c, COORD distance,
- COORD *xp, COORD *yp, COORD *zp);
-
- // This is used during rendering to extract a VIEW (window description)
- // from the camera, and set up the renderer to use it.
-
- // sets renderer to draw a view, mono or stereo view
- // also computes camera position from object it
- // is attached to
- VIEW *select_camera_view(CAMERA *c, WORD which_eye);
-
- // CAMERA view factors for stereoscopic and monoscopic views are
- // set differently. There are many support functions for mono
- // cameras, as almost any parameters make sense. For stereo,
- // there are too many interrelated factors. Most stereo
- // factors are best set up with the STEREO data structure:
- // default_stereo is set up during configuration.
- //
- // After any parameters are changed (except camera position),
- // the camera must be recomputed to cache internal coefficients:
-
- // computes the static stereo factors for camera, caches
- void compute_camera_factors(CAMERA *c);
-
- // Camera hither and yon clipping can be set in both stereo and
- // mono cameras simultaneously:
-
- // set/get hither clipping
- void set_camera_hither(CAMERA *c, COORD h);
- COORD get_camera_hither(CAMERA *c);
-
- // set/get yon clipping
- void set_camera_yon(CAMERA *c, COORD y);
- COORD get_camera_yon(CAMERA *c);
-
- // These set monoscopic "zoom" (field of view). FOV is
- // equal to 2*atan(1/zoom)
-
- // set the MONOSCOPIC zoom
- void set_camera_zoom(CAMERA *c, SCALE zoom);
-
- // get the MONOSCOPIC zoom
- SCALE get_camera_zoom(CAMERA *c);
-
- // For stereoscopic "zoom", there is no function to set
- // zoom, because many stereoscopic parameters to be changed to
- // get good stereo. Instead, adjust:
- // get_camera_stereo(CAMERA)->phys_screen_dist
- //
- // the equivalent zoom is (right-left)/2/distance
-
-
- // set the MONOSCOPIC view window on screen
- void set_camera_window(CAMERA *c, WORD l, WORD t, WORD r, WORD b);
-
- // For stereoscopic cameras, the window must be set through
- // the two windows in the camera's STEREO: example: left side:
- // get_camera_stereo(CAMERA)->window[LEFT_EYE].l
- // get_camera_stereo(CAMERA)->window[RIGHT_EYE].l
-
- // As noted, the STEREO structure controls stereo camera image generation.
- // These functions allow you to create cameras with parameters
- // different from those set into default_stereo during configuration:
-
- // this pre-initialized STEREO controls the default camera
- // usually shared by all cameras
- extern STEREO default_stereo;
-
- // make a unique (nonshared) stereo
- // parameter structure for camera
- STEREO *create_new_stereo(CAMERA *c, CAMERA *template);
-
- // pointer to camera's stereo parameter structure
- STEREO *get_camera_stereo(CAMERA *c);
-
- // makes camera use stereo parameter structure
- STEREO *set_camera_stereo(CAMERA *c, STEREO *s);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// LIGHTS: POINT, DIRECTIONAL AND AMBIENT ////
- //// (LIGHTS.C) and (COLORMAP.C) ////
- //// ////
- /////////////////////////////////////////////////////
-
- // LIGHTS may be treated as object: moved, rotated and attached
- // to other objects. Arrays of (LIGHT *) may be used to
- // light scenes, and can be used very flexibly. There are
- // 3 types of lights:
- //
- // AMBIENT_LIGHT lights all polys the same
- //
- // SPOT_LIGHT lights all polys from the same side,
- // determined by the rotation of the light: zero angle
- // lights from the +Z side
- //
- // POINT_LIGHT lights polys from a point in space, set by
- // the position of the light only.
- //
- // It is up to COLORMAP.C to decide how to cope with light data:
- // in the basic version, the total of all lights is scaled
- // to a constant 127 for integer calculations. See WPARSE.C
- // to see code for creating default lights, and USERVID.c
- // and COLORMAP.C for a sample lighting system.
-
- // create, initialize a light and its segment
- LIGHT *create_light(OBJECT *parent, WORD type, WORD intensity);
-
- // destroy a light and its segment
- // light and camera segments can only
- // be deleted through their delete functions
- void destroy_light(LIGHT *l);
-
- // returns light type
- WORD get_light_type(LIGHT *l);
-
- // returns light intensity
- WORD get_light_intensity(LIGHT *l);
-
- // sets intensity of light
- void set_light_intensity(LIGHT *l, WORD i);
-
- // sets light type
- void set_light_type(LIGHT *l, WORD t);
-
- // attaches light to an object
- // option to preserve world location
- // (see attach_object() for info on this option)
- BOOL attach_light(LIGHT *l, OBJECT *obj, BOOL preserve);
-
- // detaches light from object
- // option to preserve world location
- BOOL detach_light(LIGHT *l, BOOL preserve);
-
- // change angle of a spotlight
- // (forces light to be spotlight)
- BOOL rotate_spotlight(LIGHT *l, POSE *p);
-
- // change position of point source
- // (forces light to be point source)
- BOOL position_pointlight(LIGHT *l, POSE *p);
-
- // change pos/rot of light source
- // Makes it possible to have both point
- // and spotlight data for light
- BOOL set_light_pose(LIGHT *l, POSE *p);
-
- // get local (joint) position/angle of light
- void get_light_localpose(LIGHT *l, POSE *p);
-
- // get world position/angle of light
- void get_light_worldpose(LIGHT *l, POSE *p);
-
-
- // To actually USE the lights we've created, we must
- // pass an array of (LIGHT *) to this routine which
- // MUST be supplied by YOU. There is a sample in COLORMAP.C
-
- // usually in COLORMAP.C, sets up lights to renderer
- void setup_lights(LIGHT *llist[], WORD nlights);
-
- // fetch light data for computing
- // lighting data in COLORMAP.C
- WORD get_light_data(LIGHT *l, COORD *xp,
- COORD *yp, COORD *zp, WORD *intensity);
-
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// USER INTERFACE SUPPORT ////
- //// ////
- /////////////////////////////////////////////////////
-
- // VR-386 has many tools for user interfaces. These support:
- //
- // -keyboard responses and control
- // -mouse for object selection and manipulation
- // -"joystick" type navigation via keyboard, mouse, joystick
- // -popup message boxes and menus on screen
- // -PowerGlove and 3d/6d pointing device interfaces
- // -support for head tracking devices.
- //
- // These devices are rather basic; a standardized "pointer"
- // interface system makes development and adding of device
- // drivers easier. Pointers will be discussed elsewhere in
- // more detail, but basically consist of a simple device driver,
- // (PDRIVER) which can initialize, reset, read, and control
- // the device. Much of the functionality of a normal device
- // driver is taken over by the VR-386 pointer system, such as
- // scaling and motion detection. A data block describing the
- // device (PCONFIG) contains information of the driver's resolution,
- // range and so on.
- // Pointers support two basic modes: pointer and mouse. The idea
- // is to let any device funstion both as a pointing device
- // (2D, 3D, etc) and as a 2D mouse, scaled to the screen, for
- // use in object selection and menu selection.
- //
- // Many of the keyboard functions in this release are in
- // KEYBOARD.C, which is a large key and menu support interperter.
- // If you need to see how any VR-386 editing feature is implemented,
- // look there first. You can easily remove the KEYBOARD.C from the link,
- // as very few functions in it are critical. Only a few functions
- // are really needed, mostly Quit and the basic key processing for
- // motion control. This module basically is written to be compatible
- // with REND386 release 5.
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// USER INTERFACE SUPPORT: MOUSE, CURSOR ////
- //// ////
- /////////////////////////////////////////////////////
-
- // VR-386 uses the mouse to move a 2D cursor, or to
- // manipulate objects (the mouse-navigation is discussed
- // later). Mouse functions can be split into cursor-related
- // and menu-related, each driven by a different pointer device:
- // cursor_device and menu_device. These are usually the same.
- // Cursor drawing is implemented by the video driver.
- // (Future drivers may support multiple types of bitmap cursors).
- //
- // Before drawingto the screen, the cursor must be hidden,
- // then shown after drawing. cursor_hide() returns a flag that
- // can be saved to determine if the cursor will need to be
- // redrawn later.
-
- // If the cursor is not to be seen (mouse is not available) the
- // cursor drawing may be turned off: cursor_show is ignored.
-
- extern void cursor_enable(BOOL state); /* hardwire on/off */
-
- // The basic cursor operations are to hide and redisplay it.
- // Flags are used to ensure that a cursor is not erased or drawn
- // twice, as this will leave garbage on the screen.
- // All cursor operations are performed to the current_video_page,
- // set by the screen refresh to be the same as the displayed video page.
-
- extern BOOL cursor_hide(void); /* erase cursor, rtn visible flag */
- extern void cursor_show(void); /* redisplay cursor */
-
- // During rendering, drawing is done to a different video page,
- // and the cursor is erased from the old page and drawn to the
- // new current page after the screen refresh is done. Thus
- // a function to specify which page the cursor is to be erased
- // from is needed.
-
- extern BOOL last_cursor_hide(WORD page); /* erase cursor, on specific page */
-
- // Combining hide and redraw at a new position moves the
- // cursor on the screen:
-
- extern void cursor_move(WORD x, WORD y); /* move cursor if visible */
-
- // Integrating mouse reading and cursor motion into one
- // function. This reads the mouse once, moves the cursor and returns.
- // <d> is a pointer to a mouse driver (usually cursor_device),
- // and *x, *y, and *b will be filled with current mouse position and
- // button status: b&0x01 for left button, and b&0x02 for right.
-
- extern WORD move_2D(PDRIVER *d, WORD *x, WORD *y, WORD *b);
-
- // Adding a loop to move the mouse till a click is detected:
- // Unlike move_2D(), <b> is a mask for which buttons are to
- // be tested: 1 for left, 2 for right, 3 for both. The button
- // clicked is returned (same code).
-
- extern WORD move_till_click(PDRIVER *d, WORD b, WORD *x, WORD *y);
-
- // Often a function needs to see if the mouse is available. This returns
- // Returns 1 if true, else pops up warning message.
-
- extern BOOL can_point_2D(void);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// MOUSE AND SCREEN SELECTION OF OBJECTS ////
- //// ////
- /////////////////////////////////////////////////////
-
- // A critical feature of VR-386 is its ability to select
- // objects by simply clicking on their image on the screen.
- // The screen-to-object system can also find which polygon
- // and (if possible) vertex of the object was clicked on,
- // and is based on the screen-monitor built into the renderer.
-
- // this function reports the object which is visible at
- // that point on the screen. This is done by enabling the
- // screen monitor, refreshing the screen, then recording
- // the results. Returns NULL if no object found.
-
- OBJECT *find_object_on_screen(WORD x, WORD y);
-
- // this is called internally by find_object_on_screen to
- // process the screen monitor output:
-
- void process_screen_monitor();
-
- // The results may be read by calling these functions. The
- // poly and vertex indices are -1 if no object, poly, or
- // vertex was found. It is possible to find an object but
- // not to find a vertex.
-
- OBJECT *screen_found_object(); // object (NULL if none)
- SWORD screen_found_poly(); // poly index in object
- SWORD screen_found_poly_vertex(); // which vertex in poly (order)
- SWORD screen_found_object_vertex(); // which vertex in object (table)
-
- // This function will read the mouse once, move the cursor,
- // and check if it was clicked. If so, it checks to see
- // which object was clicked on. <*buttons> will contain
- // the button state, and NULL will be returned if no
- // button was clicked. This function should be called in a loop.
-
- OBJECT *move_and_find_object_2D(PDRIVER *d, WORD *buttons);
-
- // This function implements the core of the "screen idle" call
- // It reads the mouse once, moves the cursor, and checks for
- // a button click (left button only). Returns 0 if no click
- // or click in inactive area, -1 if menu-area click (top of screen)
- // or 1 if new object selected/deselected.
- // INSTALL EXTRA SCREEN-CLICK HANDLERS HERE.
-
- SWORD move_and_select_2D(PDRIVER *d);
-
- // THis is the main mouse-processing call for the VR-386 run loop.
- // It processes menu mouse clicks as well.
-
- extern void mouse_process();
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// SCREEN INTERFACE SUPPORT: DIALOGS, MENUS ////
- //// ////
- /////////////////////////////////////////////////////
-
-
- // reads keyboard, checks for CTRL-F10 (screen dump)
- // Encodes left/right shifts, ALT and CTRL keys
- // as modifiers on all keys. See USERINT.H for
- // key codes.
- WORD getkey(void);
-
- // saves screen to old video page
- // only done for first call after rendering
- void save_screen();
-
- // restores screen as saved by save_screen();
- // used to erase menus, text boxes, etc.
- void restore_screen();
-
- // prints box for text, centered on screen
- // with width <w> and height <h>
- void neatbox(int w, int h, int *x, int *y);
-
- // print a text box containing several lines (37 char MAX)
- // in the center of screen. Last entry of array must be NULL
- void poptext(char *text[]);
-
- // print a text box containing one line (37 char MAX)
- // at center of screen
- void popmsg(char *msg);
-
- // prints to "popmsg" box
- // useful for debugging
- // prints to stderr if not in graphics mode
- WORD popprintf(char *fmt, ...);
-
- // This is a way to get text response from user.
- // A prompt is printed, and up to <n> characters
- // are accepted. Prompt and <n> should be less than
- // 36 characters. Backspace is supported. ESC
- // will exit with an empty buffer: buff[0]==0
- // Returns exit character.
- WORD askfor(char *prompt, char *buff, WORD n);
-
- // test for response event, used to terminate waits,
- // abort loops, and so on. A joystick or mouse
- // click is accepted as a response as well as a keypress.
- // returns 0 if no response, buttons (1,2,3) for mouse,
- // 4 if joystick click, else key value
- // if <wait>, then the function will not return till
- // a response is given.
- WORD get_response(BOOL wait);
-
- // prints out menu (a NULL-terminated array of char *)
- // at center of screen. Responses should correspond to
- // the first capitalized letter in each line, which is
- // returned if the line is clicked on by mouse.
- // A click outside the menu or by joystick, or ESC exits
- // returns 0 or the capitalized letter of the selected entry.
- WORD menu(char *text[]);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// KEY PROCESSING ////
- //// ////
- /////////////////////////////////////////////////////
-
- // The key process routines must process key
- // preses, passing certain ones on to be used
- // for moving the user, and ignoring the key presses
- // that are intercepted by the key monitor. The method
- // suggested is to have a series of key processing
- // routines, as in KEYBOARD.C, that look for keys they
- // can handle, returning TRUE if they have processed the key.
-
- // The routines should be:
-
- // processes key <c>, calling sequence of key handlers
- // until one returns TRUE to mark key as processed
- void process_a_key(unsigned c);
-
- // calls getkey() to read a key, calls
- // process_a_key to handle it
- // should get first key in queue, dump others
- // to prevent type-ahead
- void key_process();
-
- // Look at the end of KEYBOARD.C for sample routines.
-
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// SCREEN REFRESH ROUTINES ////
- //// ////
- /////////////////////////////////////////////////////
-
- // Screen refresh is supported by the video driver,
- // the renderer kernal, as well as a variety of user-
- // customizable routines. The refresh is designed to support
- // monoscopic as well as several types of stereoscopic
- // views: switched (left-right alternate frames displayed),
- // windowed (seperate left and right windows on screen,
- // and seperate viddeo displays for left and right eye
- // views.
- // User customizable routines in USERVID.C are used to perform the
- // basic drawing tasks, such as lines, polygons, text,
- // and screen clearing. These provide alternates to the
- // standard video driver interface. THe polygon drawing
- // routine, in combination with the color-coding routines
- // in COLORMAP.C, allow for almost any lighting and color
- // system to be supported.
- //
- // Screen refresh proceeds in stages. First, the video page
- // to be drawn is selected. The rendering areas are then
- // prepared with a call to prerender_process(), which clears
- // the area or draws a horizon (see RENDERER.H) in the area.
- // Then the renderer itself is called to draw in the window.
- // Finally, postrender_process() is called to add overlays
- // such as status or axis compass. These routines are easily
- // customized, and are in USCREEN.C: Look at REFRESH.C to
- // see the sequence of calls. For stereoscopic rendering,
- // the sequence is repeated twice.
-
- // Routines in USERVID.C:
-
- // These are the colors used to draw in the world. For two-color
- // horizons, sky_color and ground_color set the horizon: if the
- // same. the whole window is cleared. screen_clear_color is used
- // if the screen must be completely blanked. Highlight_color
- // is used to outline selected objects.
-
- extern WORD screen_clear_color;
- extern WORD sky_color;
- extern WORD ground_color;
- extern WORD highlight_color;
-
- // call on initialization to set defaults for the colors
- // listed above. the video driver These vary depending on
- void preset_default_colors();
-
- // This structure is actually part of the video driver.
- // It has information on the driver's screen size,
- // aspect ratio and number of colors.
-
- extern struct Screeninfo *screeninfo; // ptr to data in video driver
-
- //struct Screeninfo {
- // WORD xmin; // left edge of useable area
- // WORD ymin; // top edge
- // WORD xmax; // right edge
- // WORD ymax; // bottom + 1
- // WORD xcent; //
- // WORD ycent; // where text boxes, menus should be centered
- // WORD colors; // number of colors supported
- // WORD pages; // number of video pages
- // WORD bw; // monochrome only flag
- // SCALE aspect; // vertical/horizonal pixel size * 65536
- // char id[80]; // driver title
- // };
-
-
- /********************************************************/
- /* USER ROUTINES CALLED BY THE RENDERING LIBRARY */
- /* KEEP THIS AS FAST AS POSSIBLE: SOME MAY BE */
- /* CALLED UP TO 1000 TIMES PER SCREEN! */
- /********************************************************/
-
- /* USER ROUTINE TO SETUP FOR POLY DRAWING - CALLED ONCE PER FRAME */
- void user_setup_blitter();
-
- /* USER ROUTINE TO RECOVER AFTER POLY DRAWING: ONCE PER FRAME */
- void user_reset_blitter();
-
- /* CALLED FROM RENDERER TO DRAW POLYS, LINES, POINTS */
- /* <color> was created by colormap.c: modify it to */
- /* do your own special color modes/effects! */
- // supplied data: number of points, array of (x,y) screen coords (WORD),
- // color value generated by COLORMAP.C function user_poly_color(),
- // and the depth of the deepest point in polygon.
-
- void user_render_poly(WORD number, WORD *pcoords, SURFACE color, COORD maxz);
-
- // These routines draw items for the user interface.
- // Colors are entries in the screen palette
- // All are drawn to current video page
-
- /* Draws filled box for text and menus
- // color is entry in color palette
- void user_box(WORD x1, WORD y1, WORD x2, WORD y2, WORD color);
-
- // draws a line on the screen (current page)
- void user_draw_line(WORD x1, WORD y1, WORD x2, WORD y2, WORD color);
-
- // draws a box outline on the screen (current page)
- void user_draw_box(WORD left, WORD top, WORD right, WORD bottom, WORD color);
-
- /* USER ROUTINES TO DRAW TEXT */
- // These will draw reversed text if the current page's
- // orientation requires it.
- void user_text(WORD x, WORD y, WORD color, char *string);
-
- // draws text with a black shadow (color 0)
- void shadowprint(WORD x,WORD y, WORD color, char *t);
-
- /////////////////////////////////////////////////////////////////
- /// USER VIDEO MODE SUPPORT ROUTINES:
- ///
- /// NEVER CHANGE MOST OF THESE UNLESS YOU NEED
- /// MORE THAN THE VIDEO DRIVERS CAN DO
-
- /* enter and setup graphics screen */
- // required to initialize all screens for
- // multi-VGA driver
- void enter_graphics(unsigned vdmode, int bw);
-
- /* exit and restore text screen */
- // must reset all screen for
- // multi-VGA driver
- void exit_graphics();
-
- // clear full video page: rarely needed
- void clear_display(WORD pge);
-
- // This is the "critical" function when your screen
- // has complex borders for the view window. It is
- // called when the size of the window changes, or
- // there is a chance the the border has been munged.
- // It is also called on startup.
- // If you have no border, just clear all the video
- // pges. If you have a border, redraw it on one
- // page and copy it to all other pages.
- void reset_screens();
-
-
- // IN <REFRESH.C>
-
- void screen_refresh(CAMERA *c);
-
- // This is the main screen-refresh routine. It switches video pages,
- // calls window clearing, rendering, and postrender overlay routines.
- // It draws the current world with the given camera (which also specifies
- // where on the screen it is to draw). The proper stereo mode is set by:
-
- extern WORD stereo_type;
-
- #define MONOSCOPIC 0 /* stereo types */
- #define SWITCHED 1
- #define SPLITLR 3
- #define SEPARATE 5
-
- //These variables are updated by screen_refresh():
-
- // where to save the screen while using menus
- extern WORD screen_save_video_page;
- extern BOOL screen_has_been_saved;
-
- extern WORD current_video_page; // current video page
- extern WORD current_orientation; // flip flags of current page
-
- // This routine is called by user interface routines to stop
- // the flicker of SWITCHED stereo displays.
-
- void stop_stereo();
-
- // This routine can be called by user postrender() routines to
- // draw an axis compass on the screen. Use the VIEW passed to
- // postrender()-- it contains window edges and the view matrix.
-
- // xc,yx : screen location of center
- // V : viewport structure
- // xcolor,ycolor,zcolor: color of axes
- // bcolor: "shadow" color
- void coord_ref(WORD xc, WORD yc, WORD size, VIEW *v,
- WORD xcolor, WORD ycolor, WORD zcolor, WORD bcolor);
-
-
- // Internally, screen_refresh uses this function from SCAMERA.C
- // to get monoscopic, left, or right eye views from the
- // camera to control rendering. The renderer is set up by
- // the routine to use the VIEW, and it is returned so it may be
- // passed to user routines.
-
- // sets renderer to draw a view, mono or stereo view
- // also copies segment position
- VIEW *select_camera_view(CAMERA *c, WORD which_eye);
-
-
- // IN USCREEN.C
-
- //////////////////////////////////////////
- /// THESE ROUTINES LET YOU CONTROL HOW THE
- /// SCREEN IS CLEARED AND WHAT IS DISPLAYED
- /// THE ARGUMENTS ARE:
- /// v : the view being draw. left/right eye views are different
- /// vpage: the video page being drawn
- /// isfirst, islast: 1 if this is the first/last access to the
- /// video page. Useful for toggling screen
- /// clears etc. when several views are on the
- /// same page
- /// whicheye: 0 for left eye/mono, 1 for right eye view
- ///
-
-
- // found in <USCREEN.C>
-
- // This is called before drawing objects. It should
- // at least clear the screen
-
- void prerender_process(VIEW *v, WORD vpage, WORD isfirst, WORD whicheye);
-
- // This is called after drawing objects. It can be used
- // to put up status, etc.
- // lots of if() stuff, but just because we're supporting
- // so many stereo types
-
- void postrender_process(VIEW *v, WORD vpage, WORD islast, WORD whicheye);
-
-
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// USER NAVIGATION AND JOYSTICK ////
- //// ////
- /////////////////////////////////////////////////////
-
- // The currently implemented navigation method in VR-386 uses
- // a 2D device: a joystick. Two buttons are used to map this
- // 2D to full 6D motion. Joystick "devices" include PC game
- // port, mouse, key press, and key-down monitor.
- //
- // The joystick devices are read through the regular pointer
- // interface, and are implemented in JOYPTRS.C. Up to 9
- // devices may by polled for motion (NAVJOY.C), with the sum
- // of all device's effects used to move the user.
- // All navigation devices (even key presses) are mapped
- // through pointer devices. Please look at JOYPTRS.C
- // to see how easy and flexible this tecnique is. The
- // pointer devices need only return buttons and the
- // relative (change) motion required.
-
- // Joystick devices are added with:
-
- BOOL add_joy_device(char *name);
-
- // which loads and/or initializes the pointer driver for the
- // joystick, then adds it to the list of drivers. New drivers
- // can be added or created by adding to the internal driver table
- // in POINTER.C, and adding a new pointer driver and pconfig.
-
- // The joysticks are processes to move a POSE structure to move
- // the user's body or point of view.
-
- // <body_pose> is the POSE to move user with
- // <spinmode>: if true, maps all motion to rotation
- // <sstep>: scaling of position changes: 100 is usual
- // <astep>: scales turning: angle2float(20) is usual
- // <flymode>: makes all motions relative to the
- // view direction. Otherwise, motion is relative
- // to the "ground" always.
- // RETURNS: TRUE if body has been moved by any device
-
- BOOL do_joy_navigate(POSE * body_pose, BOOL spinmode,
- COORD sstep, ANGLE astep, BOOL flymode);
-
- // The main loop of VR-386 is written to call joystick_process().
- // This routine is found at the end of KEYBOARD.C, and can easily
- // be modified to remove unwanted options.
-
- extern void joystick_process();
-
- // The usual POSE to set user position is *body_pose. This
- // is used by world and teleports as well.
-
- extern POSE initial_body_pose; // start position
- extern POSE *body_pose; // current "teleport" used
-
- // See PCDEVICE.H for more information on the PC game port joystick device.
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// USER BODY AND TELEPORTS ////
- //// ////
- /////////////////////////////////////////////////////
-
- // To use head trackers and 3D manipulators such as the PowerGlove,
- // a set of invisible connected objects is used to build the user
- // a body. The body_seg is the root of the body, which is moved
- // through the world by the navigation "joystick" devices. The body can
- // also be attached to other objects, thus letting the user "ride"
- // the object as it moves. Joystick motion is then relative to
- // the object instead of the world.
- //
- // The head tracker moves the head_seg relative to the body,
- // and the default_camera (user's viewpoint) is attached to
- // the head_seg. This is an elegant implementation of head
- // tracking.
- // There is also a wrist_seg attached to the body. It is used with
- // the PowerGlove or 3d/6d pointer devices, and used to "hold" the
- // glove or pointer 3D cursor. It is also used to manipulate objects.
- //
- // These link objects are created during initialization by a call to
-
- void init_body_links();
-
- extern OBJECT *body_seg, *wrist_seg, *head_seg;
-
- // which creates these links, and attaches the camera to the head.
- // You can easily eliminate the body code in BODY.C if you wish to have a
- // simpler viewpoint metaphor. But you will also have to eliminate
- // all head tracker, PowerGlove, and 3D pointer support device.
-
- // If the body has been moved for any reason, you must update the
- // body links so the manipulation and camera positions will be
- // current. Do this by a call to
-
- void update_body_links();
-
- // This will already have been done if the body is attached to an
- // object that was moved then updated.
-
- // To attach the body to objects, it is recommended that you use
- // these functions from BODY.C:
-
- // disconnects body from any object currently attached to
- void disconnect_body();
-
- // connects body to new ovject (disconnects old object if any)
- void connect_body(OBJECT *s);
-
- // This variable records curent object: NULL if none
- extern OBJECT *body_vehicle_object;
-
-
- // TELEPORTs are records of user positions and status.
- // They record the world, pose (as seen in *body_pose),
- // and the object the user is connected to (for moving).
- // They are used to implement the HOME key, as well as
- // the F1..F10 "cameras" (which aren't cameras, but were
- // called that in the REND386 .WLD files!).
-
- // The basic TELEPORT operations are create, delete,
- // record pose and "vehicle" object, and execute. At
- // present. between-world teleports are not implemented,
- // until WORLD support for this is implemented.
-
- // create. record present pose, world, vehicle
- TELEPORT *create_teleport();
-
- // release memory of TELEPORT
- void delete_teleport(TELEPORT *t);
-
- // record where to teleport to
- void teleport_set_here(TELEPORT *t, POSE *p);
-
- // what we're attached to at teleport entry
- void teleport_set_vehicle(TELEPORT *t, OBJECT *vehicle, char *vname);
-
- // go to the teleport position/world
- // updates *body_pose and reconnects body
- void teleport_to(TELEPORT *t);
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// POWERGLOVE, MANIPULATION AND DEVICE SUPPORT ////
- //// ////
- /////////////////////////////////////////////////////
-
- // Other than the mouse manipulation routines in KEYBOARD.C,
- // objects may be manipulated with a 3D or 6D pointer device,
- // or with the PowerGlove. These routines are well encapsulated
- // so little effort is needed to support them: just initialize
- // and call them in the main loop.
-
- // These routines should be given a driver file or internal
- // driver name, the name of a .PLG file for the 3D pointer,
- // and the name of a .FIG file for the glove's hand object.
- // The POSE is for scaling: it should contain a SCALE value
- // for all parameters. (i.e use float2scale() )
- // These are already done based on the .CFG file in INIT.C
-
- // initialize a 3D/6D pointer device
- PDRIVER *pointer_initialize(char *ptrdrv, char *ptrobj, POSE *scale);
-
- // initialize the PowerGlove
- PDRIVER *glove_initialize(char *glvdev, char *glvobj, POSE *scale);
-
- // To use the devices, simply call one of these in the main loop.
- // It reads the device, moves the image of the device, and looks
- // for button or gesture to control manipulation.
-
- // read, handle 3D/6D pointer commands
- void pointer_process();
-
- // read, handle glove gestures
- void glove_process();
-
- // Internally, the processing routines call this routine to
- // actually grasp, release, and rotate objects. The commands
- // passed depend on the current gesture or button state:
-
- // 3D/6D select/move/rotate
- void do_3D_manip(WORD command);
-
- // commands to do_3D_manip
- #define FREE_DO 0 // released
- #define GRASP_DO 1 // holding
- #define ROTATE_DO 2 // "pinch" rotation emulation for 3D dev.
- #define SELECT_DO 3 // looking for an object to grasp...
-
- // Because a pointer device works in real-world coords, with
- // Z going into screen, the pointer must be mapped to and from
- // the internal world coord system, by these functions (POINTER.C)
-
- void pointer_to_world(POINTER *p, CAMERA *c, long *x, long *y, long *z);
- void rotate_to_view( CAMERA *c, long *x, long *y, long *z);
-
-
-
- // For reportingthe current glove gesture, this function is useful:
-
- // returns text string with gesture,
- // or NULL if no glove
- char *get_glove_gesture_name();
-
- // Finally, we need a way to initialize the head tracker device.
- // This function does that, given a driver file or device name.
- // The POSE is the head tracker "offset": a matrix used to
- // compensate for tilt and offset of tracker with respect
- // to the user's head.
-
- PDRIVER *init_head_device(char *dfname, POSE *hdo);
-
- // and to process the tracker data :
-
- void head_tracker_process();
-
- // the PDRIVER arguments may be ignored as the driver address
- // is kept internally by the support modules. However, if NULL
- // is returned by the initiializing functions, the driver could not
- // be initialized.
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// INITIALIZATION AND PROGRAMS ////
- //// ////
- /////////////////////////////////////////////////////
-
- // FOR OTHER INITIALIZATIONS, LOOK AT INIT.C, PCDEVICE.H ETC.
- // SEE ALSO EXAMPLES IN MAIN.C
-
- // alternate-frame stero driver start
- // may take over timer
- void init_switch_driver(char * swdname);
-
- //////// FROM INIT.C
-
- // sets up renderer, memory, load video driver
- // Also reads config file, loads video driver
- void preload_initialize(int argc, char *argv[]);
-
- // read configuration. mark loadable file args
- // loads .CFG flie, calls EMM init if used
- void read_configuration(int argc, char *argv[]);
-
- // This calls:
- void read_config_file(FILE *in);
-
- // read input files from cmd line
- // loads .PLG, .WLD, and .FIG
- void read_input_files(int argc, char *argv[]);
-
-
- // (WPARSE.C) This can load REND386 v5 .WLD files via a call to:
- void read_world(FILE *in);
- // and retrieves name list memory later with a call to
- void dump_lists();
-
- // If you want to use the standard lights, use this code from WPARSE.C
- // It creates the standard lights: one ambient, two point sources.
- void create_default_lights();
-
- extern LIGHT *std_lights[3];
- extern LIGHT *amb_light;
- extern LIGHT *light1;
- extern LIGHT *light2;
-
- // report on memory use after loading
- // reports EMM use as well
- void load_memory_report();
-
- // initialize video system, enter graphics mode
- void video_initialize();
-
- // initialize all hardware devices and pointers
- void device_initialize();
-
- // call at exit to reset all to DOS mode
- void exit_handler(void); /* end program */
-
-
- /// MAIN PROGRAM: SHOULD:
-
- // - call above initialization routines
- // - set up any devices or items not set up by above.
- // - start main loop, until running==FALSE:
-
- extern BOOL running;
- extern BOOL in_graphics;
-
- // Main loop should do (in this order)
-
- // key scan, process keys for key joystick etc
- extern void key_process();
-
- // read and proccess joystick navigation devices to move user
- extern void joystick_process();
-
- // move cursor, select objects or menu commands
- extern void mouse_process();
-
- // CALL ONLY IF THESE DEVICES ARE ACTIVE
- extern void head_tracker_process(BOOL recenter);
- extern void glove_process();
- extern void pointer_process();
-
- // run any tasks, animations, etc.
- // also, update any objects changed by animation
-
- // Now, refresh display if required.
- // There are several flags which should be set
- // if anything changes, and cleared when the
- // screen is redrawn:
-
- extern WORD world_changed, display_changed, position_changed;
-
- // Suggested refresh:
- //
- // update_body_links();
- // screen_refresh(current_camera);
- // position_changed = 0;
- // world_changed = 0;
- // display_changed = 0;
-
- // SEE MAIN.C FOR EXAMPLE.
-
-
- /////////////////////////////////////////////////////
- //// ////
- //// OTHER FUNCTIONS ////
- //// ////
- /////////////////////////////////////////////////////
-
- // ERROR REPORTING
-
- extern FILE *log_file; // error log file, opened in read_cfg
-
- // print error message in appropriate way(s)
- WORD errprintf(char *fmt, ...);
-
- // FILE NAME SUUPPORT
-
- // add extension to filename
- void add_ext(char *name, char *ext);
-
- extern char loadpath[100]; // default load path
-
- // adds default load path to filename
- char *fix_fname(char *name);
-
- ////////// PCXMODEY.C
-
- // load, save full-screen PCX file
- load_pcx(FILE *in, int page);
-
- save_pcx(FILE *out, int page);
-
-
- //////////// DRVLOAD.C
-
- // load a video or pointer driver
- void *load_driver(char *dfile);
-
-
- ////// THESE ARE ALSO IN PCDEVICE.H
-
- extern void tdelay(long msec); /* replaces borland delay() */
- extern long current_time(void); /* returns time in msec */
- // returns count per int, speed is a hint (0 for default)
- extern int init_timer(unsigned speed, void (*timer_hook)());
- extern int init_frame_lock(unsigned speed, void (*frame_hook)());
-
- extern int get_ticks_per_second(void); // always returns 1000
-
-
-